/* Имя: osccal.c
 * Автор: Christian Starkjohann
 * Перевод: microsin.ru 
 * Дата создания: 2008-04-10
 * Табуляция: 4
 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
 * Лицензия: GNU GPL v2 (см. License.txt) или проприетарная (CommercialLicense.txt)
 * Ревизия: $Id: osccal.c 553 2008-04-17 19:00:20Z cs $
 */

#include <avr/io.h>
#include "usbdrv.h"

/* ------------------------------------------------------------------------- */
/* -------------------- Калибровка тактового генератора -------------------- */
/* ------------------------------------------------------------------------- */

/* Функция калибрует RC-генератор. Наш опорный источник точного времени - 
 *  сигнал SOF, Start Of Frame (один бит SE0), повторяющийся каждую милисекунду
 *  сразу после состояния USB RESET. Мы сначала делаем двоичный поиск величины
 *  OSCCAL, и затем оптимизируем эту величину поиском соседних значений.
 *  Этот алгоритм может также использоваться для калибровки RC-генератора напрямую
 *  до 12 MHz (не вовлекается ФАПЧ, таким образом эту технику можно использовать 
 *  почти на ВСЕХ AVR), но это слишком вне спецификации величины OSCCAL и необходимой 
 *  точности для тактов на 12 МГц! Используйте RC-генератор, калиброванный на 12 МГц
 *  только для экспериментов!
 */
void    calibrateOscillator(void)
{
	uint8_t		step = 128;
	uint8_t		trialValue = 0, optimumValue;
	int			x, optimumDev, targetValue = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5);

    /* делаем двоичный поиск: */
    do{
        OSCCAL = trialValue + step;
        x = usbMeasureFrameLength();    /* пропорционально текущей реальной частоте */
        if(x < targetValue)             /* частота еще слишком низкая */
            trialValue += step;
        step >>= 1;
    }while(step > 0);
    /* Здесь мы имеем точность +/- 1 от оптимального OSCCAL */
    /*  теперь ищем соседнее значение для оптимальной величины */
    optimumValue = trialValue;
    optimumDev = x; /* это конечно очень далеко от оптимума */
    for(OSCCAL = trialValue - 1; OSCCAL <= trialValue + 1; OSCCAL++){
        x = usbMeasureFrameLength() - targetValue;
        if(x < 0) x = -x;
        if(x < optimumDev)
		{
            optimumDev = x;
            optimumValue = OSCCAL;
        }
    }
    OSCCAL = optimumValue;
}
/*
Замечание: Этот алгоритм калибровки может пробовать 
величины OSCCAL до 192, даже если оптимальная величина далеко меньше 192. 
Таким образом, может быть превышена допустимая тактовая частота CPU в разработках 
с низковольтным питанием! Вы можете заменить этот алгоритм поиска любым другим
алгоритмом по Вашему желанию, если Вы имеете дополнительные ограничения как,
например, максимальная частота CPU.
Для RC-генераторов версий 5.x (у которых диапазон регулировки склеен из 2x128 
шагов, например ATTiny25, ATTiny45, ATTiny85), может быть полезно искать оптимум 
в обеих областях.
*/
